
#include "mxd_uam_drv.h"

#define UAMDRV_TX_BUF_LEN    256
#define UAMDRV_RX_BUF_LEN    256

#define UAMDRV_PWM_PERIOD    12
#define UAMDRV_PWM_PLUS      6

#define UAMDRV_ENABLE_RETRY
#define UAMDRV_ENABLE_RXBYTES
// 
#define UAMDRV_USE_TIMER

int UAMDRV_ETU_TIMER_CNT = 372;
#ifdef UAMDRV_USE_TIMER
int UAMDRV_HALF_ETU_TIMER_CNT = 186;
#else
int UAMDRV_HALF_ETU_TIMER_CNT = 100;
#endif

int gTxLen;
int gRxLen;
int gRxReady;
int gTxRx;
char gTxBuf[UAMDRV_TX_BUF_LEN];
char gRxBuf[UAMDRV_RX_BUF_LEN];

extern int cmmbdrv_log;
#define UAMDRV_TRACE_LEN  256
void UAMDRV_TRACE(const char *pFormat, ...)
{
    char *ptr;
    va_list args;
    static char buf[UAMDRV_TRACE_LEN];
    int len;

    if (cmmbdrv_log == 0)
    {
        return;
    }

    va_start(args, pFormat);
    len = _vsnprintf((char *)buf, UAMDRV_TRACE_LEN - 1, pFormat, args);
    ptr = buf;

#if 0
    while (*ptr)
    {
        din2_50SendByteOnUart(*ptr++, 0);
    }
#else
    tra1_2TraceApplOutput(PROCESS_ENV, 0, 0xFF, (u8*)buf, (s16)UAMDRV_TRACE_LEN, &len);
#endif
    va_end(args);
}/* end of MMBBMS_OSL_Trace() */

void UAMDRV_RxTx2(void)
{
    static int rindex = 0;
    static int tindex = 0;
    static int retry = 0;
    static int bitcnt = 0;
    static char parity = 0;
    static char data = 0;
    
    if (gTxRx == 0)
    {/* Send */
        switch (bitcnt)
        {
            case 0:
                {
                    data = gTxBuf[tindex];
                    parity = 0;
                    ISO7816_IO_OUTPUT();
                    /* one start bit */
                    ISO7816_CLR_IO();

                    break;
                }
            case 9:
                {
                    /* one parity bit */
                    if ((parity & 0x01) == 0x01)
                    {
                        ISO7816_SET_IO();
                    }
                    else
                    {
                        ISO7816_CLR_IO();
                    }

                    break;
                }
            case 10:
                {
                    /* prepare for reading ack */
                    ISO7816_IO_INPUT();
                    break;
                }
            case 11:
                {
                    if (ISO7816_IO_VALUE() == 0)
                    {/* failed */
                        {
                            gRxLen = 0;
                            gRxReady = 1;
                            gTxLen = tindex;
                            bitcnt = 0;
                            tindex = 0;
                            kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);
                        }

                        return;
                    }
                    else
                    {
                        tindex++;

                        if (tindex >= gTxLen)
                        {
                            tindex = 0;
                            gTxRx = 1;
                            rindex = 0;
                            //kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);
                            //ISO7816_IO_ENAISR();
                            // 
                            {
                                t_SCTUTimerData     ktTimerData;
    
                                KID_ConfigTimer(&ktTimerData,
                                                SCTU_TIM_MODE_RESTART,
                                                SCTU_TIM_MODE_RELOAD,
                                                UAMDRV_HALF_ETU_TIMER_CNT);
    
                                kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_START, &ktTimerData);
                            }
                        }

                        bitcnt = 0;
                        retry = 0;
                    }

                    return;
                }
            default:
                {
                    if ((data & 0x01) == 0x01)
                    {
                        ISO7816_SET_IO();
                    }
                    else
                    {
                        ISO7816_CLR_IO();
                    }

                    parity ^= (data & 0x01);
                    data >>= 1;
                    break;
                }
        }

        bitcnt++;
    }
    else
    {/* Receive */
        switch (bitcnt)
        {
            case 0:
                {/* delay one and half bit */
                    if (ISO7816_IO_VALUE())
                    {/* wait for start bit */
                        return;
                    }
                    else
                    {
                        t_SCTUTimerData     ktTimerData;

                        KID_ConfigTimer(&ktTimerData,
                                        SCTU_TIM_MODE_RESTART,
                                        SCTU_TIM_MODE_RELOAD,
                                        UAMDRV_ETU_TIMER_CNT);

                        kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_START, &ktTimerData);
                    }

                    data = 0;
                    parity = 0;

                    break;
                }
            case 9:
                {
                    /* one parity bit */
                    if (ISO7816_IO_VALUE())
                    {
                        parity ^= 0x01;
                    }

                    break;
                }
            case 10:
                {
                    if (parity != 0)
                    {/* failed */
                        /*
                        if (retry < 1)
                        {
                            ISO7816_IO_OUTPUT();
                            ISO7816_CLR_IO();
                            bitcnt = 12;
                            retry++;
                        }
                        else
                        */
                        {
                            gRxLen = rindex;
                            gRxReady = 1;
                            bitcnt = 0;
                            rindex = 0;
                            retry = 0;
                            gTxRx = 0;
                            kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);
                        }

                        return;
                    }
                    else
                    {
                        retry = 0;
                    }
                    /* not use "break" here */
                }
            case 11:
                {
                    bitcnt = 0;
                    gRxBuf[rindex] = data;
                    kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);

                    rindex++;

                    if (rindex >= gRxLen)
                    {
                        gTxRx = 0;
                        rindex = 0;
                        gRxReady = 1;
                    }
                    else
                    {
                        //ISO7816_IO_ENAISR();
                        {
                            t_SCTUTimerData     ktTimerData;
    
                            KID_ConfigTimer(&ktTimerData,
                                            SCTU_TIM_MODE_RESTART,
                                            SCTU_TIM_MODE_RELOAD,
                                            UAMDRV_HALF_ETU_TIMER_CNT);
    
                            kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_START, &ktTimerData);
                        }
                    }

                    return;
                }
            case 12:
                {
                    t_SCTUTimerData     ktTimerData;

                    ISO7816_SET_IO();
                    ISO7816_IO_INPUT();
                    bitcnt = 0;
                    KID_ConfigTimer(&ktTimerData,
                                    SCTU_TIM_MODE_RESTART,
                                    SCTU_TIM_MODE_RELOAD,
                                    UAMDRV_HALF_ETU_TIMER_CNT);
    
                    kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_START, &ktTimerData);

                    return;
                }
            default:
                {/* 8 bits */
                    data >>= 1;

                    if (ISO7816_IO_VALUE())
                    {
                        data |= 0x80;
                        parity ^= 0x01;
                    }

                    break;
                }
        }

        bitcnt++;
    }
}

void UAMDRV_RxTx(void)
{
    static int index = 0;
    static int bitcnt = 0;
    static char parity = 0;
    static char data = 0;
#ifdef UAMDRV_ENABLE_RXBYTES
    static int rdcnt = 0;
#endif
#ifdef UAMDRV_ENABLE_RETRY
    static int retry = 0;
#endif
    if (gTxRx == 0)
    {/* Send */
        switch (bitcnt)
        {
            case 0:
                {
                    data = gTxBuf[index];
                    parity = 0;
                    ISO7816_IO_OUTPUT();
                    /* one start bit */
                    ISO7816_CLR_IO();

                    break;
                }
            case 9:
                {
                    /* one parity bit */
                    if ((parity & 0x01) == 0x01)
                    {
                        ISO7816_SET_IO();
                    }
                    else
                    {
                        ISO7816_CLR_IO();
                    }

                    break;
                }
            case 10:
                {
                    /* prepare for reading ack */
                    ISO7816_IO_INPUT();
                    break;
                }
            case 11:
                {
                    if (ISO7816_IO_VALUE() == 0)
                    {/* failed */
/*
#ifdef UAMDRV_ENABLE_RETRY

                        if (retry < 3)
                        {
                            bitcnt = 12;
                            retry++;
                        }
                        else
#endif
*/
                        {
                            gRxLen = 0;
                            gRxReady = 1;
                            gTxLen = index;
                            bitcnt = 0;
                            index = 0;
                            kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);
                        }

                        return;
                    }
                    else
                    {
                        index++;

                        if (index == gTxLen)
                        {
                            index = 0;
                            gTxRx = 1;
                        #ifdef UAMDRV_ENABLE_RXBYTES
                            rdcnt = 0;
                        #endif
                            kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);
                            ISO7816_IO_ENAISR();
                        }

                        bitcnt = 0;
					#ifdef UAMDRV_ENABLE_RETRY
                        retry = 0;
					#endif
                    }

                    return;
                }
            case 12:
                {
                    bitcnt = 0;
                    return;
                }
            default:
                {
                    if ((data & 0x01) == 0x01)
                    {
                        ISO7816_SET_IO();
                    }
                    else
                    {
                        ISO7816_CLR_IO();
                    }

                    parity ^= (data & 0x01);
                    data >>= 1;
                    break;
                }
        }

        bitcnt++;
    }
    else
    {/* Receive */
        switch (bitcnt)
        {
            case 0:
                {/* delay one and half bit */
                #ifdef UAMDRV_ENABLE_RXBYTES
                    if (rdcnt != 0)
                    {
                        if (ISO7816_IO_VALUE())
                        {
                            bitcnt = -1;
                        }
                    }
                    else
                #endif
                    {
                        if (ISO7816_IO_VALUE())
                        {
                            gRxLen = index;
                            gRxReady = 1;
                            bitcnt = 0;
                            index = 0;
                            gTxRx = 0;
                            return;
                        }
                        else
                        {
                            t_SCTUTimerData     ktTimerData;

                            KID_ConfigTimer(&ktTimerData,
                                            SCTU_TIM_MODE_RESTART,
                                            SCTU_TIM_MODE_RELOAD,
                                            UAMDRV_ETU_TIMER_CNT);
    
                            kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_START, &ktTimerData);
                        }
                    }

                    data = 0;
                    parity = 0;
                }
            case 9:
                {
                    /* one parity bit */
                    if (ISO7816_IO_VALUE())
                    {
                        parity ^= 0x01;
                    }

                    break;
                }
            case 10:
                {
                    if (parity != 0)
                    {/* failed */
/*
#ifdef UAMDRV_ENABLE_RETRY
                        if (retry < 2)
                        {
                            ISO7816_IO_OUTPUT();
                            ISO7816_CLR_IO();
                            bitcnt = 12;
                            retry++;
                        }
                        else
#endif
*/
                        {
                            gRxLen = index;
                            gRxReady = 1;
                            bitcnt = 0;
                            index = 0;
                            gTxRx = 0;
                            kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);
                        }

                        return;
                    }
                #ifdef UAMDRV_ENABLE_RETRY
					else if((gRxLen == 21) && (index >2) && (index < 19))
                    {/* cw data */
					#ifdef UAMDRV_ENABLE_RXBYTES
                        if (rdcnt == 0)
						{
                    #endif
						if (retry == 0)
						{/* read again */
							ISO7816_IO_OUTPUT();
							ISO7816_CLR_IO();
							gRxBuf[index] = data;
							bitcnt = 12;
							retry++;

							return;
						}
						else
						{
							if(gRxBuf[index] != data)
							{
								gRxLen = index;
								gRxReady = 1;
								bitcnt = 0;
								index = 0;
								gTxRx = 0;
								kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);

								return;
							}
						}
					#ifdef UAMDRV_ENABLE_RXBYTES
						}
                    #endif
					}
                #endif
					break;
                }
            case 11:
                {
                    bitcnt = 0;
				#ifdef UAMDRV_ENABLE_RETRY
                    retry = 0;
				#endif
                    gRxBuf[index] = data;

                    index++;

                    if (index == gRxLen)
                    {
                        kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);
                        gTxRx = 0;
                        index = 0;
                        gRxReady = 1;
                    }
                    else
                    {
                    #ifdef UAMDRV_ENABLE_RXBYTES
                        if((gRxLen == 21) && (index > 3) && (rdcnt < 2))
                        {
                            rdcnt++;
                        }
                        else
                    #endif
                        {
                            kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);
                        #ifdef UAMDRV_ENABLE_RXBYTES
                            rdcnt = 0;
                        #endif

                            ISO7816_IO_ENAISR();
                        }
                    }

                    return;
                }
            case 12:
                {
                    ISO7816_SET_IO();
                    ISO7816_IO_INPUT();
                    bitcnt = 0;
                    kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);
                    ISO7816_IO_ENAISR();
                    return;
                }
            default:
                {/* 8 bits */
                    data >>= 1;

                    if (ISO7816_IO_VALUE())
                    {
                        data |= 0x80;
                        parity ^= 0x01;
                    }

                    break;
                }
        }

        bitcnt++;
    }
}

void UAMDRV_InterruptTreatment(void)
{
    t_SCTUTimerData     ktTimerData;

    KID_ConfigTimer(&ktTimerData,
                    SCTU_TIM_MODE_RESTART,
                    SCTU_TIM_MODE_RELOAD,
                    UAMDRV_HALF_ETU_TIMER_CNT);

    kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_START, &ktTimerData);

    ISO7816_IO_DISISR();
}

void UAMDRV_InterruptReg(void)
{
    t_EXTINTCFGInitData itConfig;
    t_kidRegisterFunc   registerDat;

    UAMDRV_TRACE("<UAM_DRV> Enter UAMDRV_InterruptReg()\r\n");

    kid3_04Ioctl(EXTINT, UAM_SIM_INTERRUPT , EXTINT_IOCTL_DISABLE_EXT_INTERRUPT , (int32_t *) EXTINT_IRQ2);
    itConfig.ucMode = EXTINT_MODE_DEBOUNCE;
    itConfig.ucDeb = EXTINT_NO_DEBOUNCE;

    itConfig.ucPol = EXTINT_POLARITY_FALLING_EDGE_LOW_LEVEL;
    itConfig.ucSel = EXTINT_PIN_0_SELECTED;

    kid3_04Ioctl(EXTINT, UAM_SIM_INTERRUPT, EXTINT_IOCTL_CONFIGURE_EXT_INTERRUPT, &itConfig);

    registerDat.ulIntId = UAM_SIM_INTERRUPT;
    registerDat.pfnUser = UAMDRV_InterruptTreatment;
    kid3_04Ioctl(EXTINT, EXTINT_IRQ2, EXTINT_IOCTL_REGISTER_USER_FUNC, &registerDat);
    kid3_04Ioctl(EXTINT, UAM_SIM_INTERRUPT , EXTINT_IOCTL_DISABLE_EXT_INTERRUPT , (int32_t *) EXTINT_IRQ2);
}

/**********************************************************************/
//#define DEBUG_UAM_FTR
int MXD_ISO7816_Transf(char *pTxData, int txLen, char *pRxData, int rxLen)
{
    int cnt = 0;
    t_SCTUTimerData     ktTimerData;
#if defined(DEBUG_UAM_FTR)
    UAMDRV_TRACE("<UAM_DRV> Enter MXD_ISO7816_Transf() tx:%d, rx:%d\r\n", txLen, rxLen);

    for (cnt = 0; cnt < txLen; cnt++)
    {
        UAMDRV_TRACE("0x%x,", pTxData[cnt]);
    }

    UAMDRV_TRACE("\r\n");
#endif
    memcpy(gTxBuf, pTxData, txLen);
    gTxLen = txLen;
    gRxLen = rxLen;

    gRxReady = 0;
    gTxRx = 0;


    KID_ConfigTimer(&ktTimerData, SCTU_TIM_MODE_RESTART,
                    SCTU_TIM_MODE_RELOAD,
                    UAMDRV_ETU_TIMER_CNT);

    kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_START, &ktTimerData);
    cnt = 0;

    while (gRxReady == 0)
    {
        MC_UTSER_SLEEP(UTSER_1MSEC_PRECISION, 15);
        cnt++;

        if (cnt >= 100)
        {
        #ifdef UAMDRV_USE_TIMER
            kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);
        #else
            ISO7816_IO_DISISR();
        #endif
            UAMDRV_TRACE("<UAM_DRV> Recv Timeout!!!\r\n");
            return 0;
        }
    }

    MC_UTSER_SLEEP(UTSER_1MSEC_PRECISION, 10);

    if (txLen != gTxLen)
    {
        UAMDRV_TRACE("<UAM_DRV> Send Err: Aim:%d, Act:%d\r\n", txLen, gTxLen);
        return 0;
    }
    else if (gRxLen != rxLen)
    {
        UAMDRV_TRACE("<UAM_DRV> Recv Err: Aim:%d, Act:%d\r\n", rxLen, gRxLen);
        return 0;
    }
    else
    {
        memcpy(pRxData, gRxBuf, gRxLen);
        /*
        UAMDRV_TRACE("<UAM_DRV> Transf OK, TxLen:%d, RxLen:%d !\r\n", gTxLen, gRxLen);
        for(cnt = 0; cnt < gRxLen; cnt++)
        {
            UAMDRV_TRACE("0x%x,", pRxData[cnt]);
        }
        UAMDRV_TRACE("\r\n");
        */
        return gRxLen;
    }
}/* end of MXD_ISO7816_ReadData() */

void MXD_ISO7816_ChangeBaud(void)
{
    char pps[4] = {0xFF, 0x10, 0x94, 0x00};
    char rsp[4] = {0};

    UAMDRV_TRACE("<UAM_DRV> Enter MXD_ISO7816_ChangeBaud()\r\n");

    UAMDRV_ETU_TIMER_CNT = 372;
    UAMDRV_HALF_ETU_TIMER_CNT = 100;

    pps[3] = pps[0] ^ pps[1] ^ pps[2];
    MXD_ISO7816_Transf(pps, 4, rsp, 4);

    UAMDRV_ETU_TIMER_CNT = 64;
    UAMDRV_HALF_ETU_TIMER_CNT = 10;
}/* end of MXD_ISO7816_ChangeBaud() */

void MXD_ISO7816_Reset(void)
{
    din2_36Gpio(UAM_SIM_RST, DIN_PORT_LOW);
    MC_UTSER_SLEEP(UTSER_1MSEC_PRECISION, 150);
    din2_36Gpio(UAM_SIM_RST, DIN_PORT_HIGH);
    MC_UTSER_SLEEP(UTSER_1MSEC_PRECISION, 350);
}
void MXD_ISO7816_Init(void)
{
    t_kidSetModulationData ioCtl;
    t_kidRegisterFunc   ktRegisterFunc;
    int cguDev = 0x2000;

    UAMDRV_TRACE("<UAM_DRV> Enter MXD_ISO7816_Init() before CMMB_Delay(200)\r\n");
    CMMB_Delay(200);
    UAMDRV_TRACE("<UAM_DRV> Enter MXD_ISO7816_Init() end CMMB_Delay(200)\r\n");

#ifndef UAMDRV_USE_TIMER
    UAMDRV_InterruptReg();
#endif

    /*
     * Turn on pwm0
     */
    kid3_04Ioctl(CGU, 0, CGU_IOCTL_SET_SC_DEVICE_CLOCK_ON, (void*)cguDev);
    ioCtl.usPeriodValue = UAMDRV_PWM_PERIOD;
    ioCtl.usTimerValue = UAMDRV_PWM_PLUS;
    ioCtl.ucMode = 0;
#if defined(FT_CMMB_UAM_PWM2_CONTROL_FTR)    
    kid3_04Ioctl(PWM, 2, PWM_IOCTL_SET_PERIOD_AND_TIMER, &ioCtl);
#else
    kid3_04Ioctl(PWM, 0, PWM_IOCTL_SET_PERIOD_AND_TIMER, &ioCtl);
#endif

#ifdef UAMDRV_USE_TIMER
    KID_RegUserFunc(&ktRegisterFunc, SCTU_TIM_OVERFLOW, UAMDRV_RxTx2);
#else
    KID_RegUserFunc(&ktRegisterFunc, SCTU_TIM_OVERFLOW, UAMDRV_RxTx);
#endif
    kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_REGISTER_USER_FUNC, &ktRegisterFunc);
    INTC1_17RegisterIST(INTHDL_IID_SCTU1, SCTU1_00IST);

    din2_37SetGpioDir(UAM_SIM_RST, DIN_PORT_OUTP);
    din2_37SetGpioDir(UAM_SIM_IO, DIN_PORT_INP);

    /*
     * Reset Device
     */
    MXD_ISO7816_Reset();
    //MXD_ISO7816_ChangeBaud();
}/* end of MXD_ISO7816_Init() */

void MXD_ISO7816_DeInit(void)
{
    t_kidSetModulationData ioCtl;
    int cguDev = 0x2000;;

    UAMDRV_TRACE("<UAM_DRV> Enter MXD_ISO7816_DeInit()\r\n");

    /*
     * Turn off pwm0
     */
    ioCtl.usPeriodValue = 0;
    ioCtl.usTimerValue = 0;
    ioCtl.ucMode = 0;
#if defined(FT_CMMB_UAM_PWM2_CONTROL_FTR)        
    kid3_04Ioctl(PWM, 2, PWM_IOCTL_SET_PERIOD_AND_TIMER, &ioCtl);
#else
    kid3_04Ioctl(PWM, 0, PWM_IOCTL_SET_PERIOD_AND_TIMER, &ioCtl);
#endif
    kid3_04Ioctl(CGU, 0, CGU_IOCTL_SET_SC_DEVICE_CLOCK_OFF, (void*)cguDev);

    din2_37SetGpioDir(UAM_SIM_RST, DIN_PORT_OUTP);
    din2_37SetGpioDir(UAM_SIM_IO, DIN_PORT_OUTP);
    din2_36Gpio(UAM_SIM_RST, DIN_PORT_LOW);
    din2_36Gpio(UAM_SIM_IO, DIN_PORT_LOW);

    ISO7816_IO_DISISR();
    kid3_04Ioctl(SCTU, 1, SCTU_IOCTL_SET_TIMER_STOP, 0);

}/* end of MXD_ISO7816_DeInit() */



